#include <UnitTest++.h>

#include "../SpellCore.Interop/SpellCore.Interop.h"

#include <shlobj.h>

struct TestSpellCheckerFixture {
  // This requires SpellCore to be set up correctly with test dictionary!

  //Setup
  TestSpellCheckerFixture(){
    // reset personal dictionary for test 
  // test dictionary must not contain the word "palavra"
  // test dictionary must contain the word "word"

    hChecker = CreateSpellChecker(L"test");
    AddGoodWord(hChecker, L"word", 4);

  }
  //Teardown
  ~TestSpellCheckerFixture(){
    FreeSpellChecker(hChecker);
    DeletePersonalDictionary();
  }
  HSCCHECKER hChecker;

  void DeletePersonalDictionary(){
    LPITEMIDLIST pidlDocFiles; 
    if( S_OK == SHGetFolderLocation(NULL, CSIDL_MYDOCUMENTS, NULL, 0, &pidlDocFiles)){
      wchar_t szPersonalDictionaryFile[MAX_PATH];
      if(SHGetPathFromIDList(pidlDocFiles, szPersonalDictionaryFile)){
        std::wstring s(szPersonalDictionaryFile);
        s += L"\\SpellCore\\test\\Ascens\\test.dic";
        DeleteFile(s.c_str());
      }
    }
  }
};


TEST_FIXTURE(TestSpellCheckerFixture, CreateSpellChecker_GoodId_NotNull){
  CHECK(hChecker != NULL);
}

TEST(CreateSpellChecker_NullId_NullHandle){
  HSCCHECKER hChecker = CreateSpellChecker(NULL);
  CHECK_EQUAL((HSCCHECKER)NULL, hChecker);
}

TEST(CreateSpellChecker_EmptyId_NullHandle){
  HSCCHECKER hChecker = CreateSpellChecker(L"");
  CHECK_EQUAL((HSCCHECKER)NULL, hChecker);
}


TEST(FreeSpellChecker_HandleNull_NoCrash){
  FreeSpellChecker(NULL);
  testResults_;
}

TEST(CanCheckSpelling_UnknownWritingSystemId_False){
  HSCCHECKER hChecker = CreateSpellChecker(L"deleteme");

  CHECK_EQUAL((BOOL)false, CanCheckSpelling(hChecker));

  FreeSpellChecker(hChecker);
}

// This requires SpellCore to be set up correctly with test dictionary!
TEST_FIXTURE(TestSpellCheckerFixture, CanCheckSpelling_KnownWritingSystemId_False){
  CHECK_EQUAL((BOOL)true, CanCheckSpelling(hChecker));
}

// This requires SpellCore to be set up correctly with test dictionary that does not contain palavra
TEST_FIXTURE(TestSpellCheckerFixture, AddGoodWord_NoCrash){
  CHECK_EQUAL(CheckingResultUnknown, GetWordStatus(hChecker, L"palavra", 7));
  AddGoodWord(hChecker, L"palavra", 7);
  CHECK_EQUAL(CheckingResultGood, GetWordStatus(hChecker, L"palavra", 7));
}

TEST_FIXTURE(TestSpellCheckerFixture, AddGoodWord_Null_NoCrash){
  AddGoodWord(hChecker, NULL, 4);
  testResults_;
}

TEST_FIXTURE(TestSpellCheckerFixture, AddGoodWord_0Size_NoCrash){
  AddGoodWord(hChecker, L"word", 0);
  testResults_;
}

TEST_FIXTURE(TestSpellCheckerFixture, AddGoodWord_Empty_NoCrash){
  AddGoodWord(hChecker, L"", 0);
  testResults_;
}

TEST_FIXTURE(TestSpellCheckerFixture, GetWordStatus_Empty_Unknown){
  CHECK_EQUAL(CheckingResultUnknown, GetWordStatus(hChecker, L"", 0));
}

TEST_FIXTURE(TestSpellCheckerFixture, GetWordStatus_NULL_Unknown){
  CHECK_EQUAL(CheckingResultUnknown, GetWordStatus(hChecker, NULL, 4));
}

TEST_FIXTURE(TestSpellCheckerFixture, GetWordStatus_0Size_Unknown){
  CHECK_EQUAL(CheckingResultUnknown, GetWordStatus(hChecker, L"word", 0));
}

// This requires SpellCore to be set up correctly with test dictionary that contains word!
TEST_FIXTURE(TestSpellCheckerFixture, GetWordStatus_WordExists_KnownGood){
  CHECK_EQUAL(CheckingResultGood, GetWordStatus(hChecker, L"word", 4));
}


// This requires SpellCore to be set up correctly with test dictionary that contains suggestions!
TEST_FIXTURE(TestSpellCheckerFixture, GetSuggestions_WordExists_IncludesWordInSuggestionList){
    HSCSUGGESTIONLIST hSuggestions = GetSuggestions(hChecker, L"wurd", 4);
    CHECK(hSuggestions != NULL);

    const UINT cchBuffer = 256; //outlandishly large for a single word
    wchar_t* buffer = new wchar_t[cchBuffer]; 
    long score;
    CHECK_EQUAL((BOOL)true, GetNextSuggestion(hSuggestions, buffer, cchBuffer, &score));
    CHECK_EQUAL(-1, score);
    CHECK(std::wstring(L"word") == std::wstring(buffer));

    CHECK_EQUAL((BOOL)false, GetNextSuggestion(hSuggestions, buffer, cchBuffer, &score));
    delete[] buffer;
    FreeSuggestions(hSuggestions);
}

// need a test for more than one suggestion returned

TEST(GetNextSuggestion_NullHandle_False){
    const UINT cchBuffer = 256; //outlandishly large for a single word
    wchar_t* buffer = new wchar_t[cchBuffer]; 
    long score;
    CHECK_EQUAL((BOOL)false, GetNextSuggestion(NULL, buffer, cchBuffer, &score));
    delete[] buffer;
}

TEST_FIXTURE(TestSpellCheckerFixture, GetNextSuggestion_NullBuffer_False){
    HSCSUGGESTIONLIST hSuggestions = GetSuggestions(hChecker, L"word", 4);
    const UINT cchBuffer = 256; //outlandishly large for a single word
    long score;
    CHECK_EQUAL((BOOL)false, GetNextSuggestion(hSuggestions, NULL, cchBuffer, &score));
    FreeSuggestions(hSuggestions);
}

TEST_FIXTURE(TestSpellCheckerFixture, GetNextSuggestion_BufferTooSmall_False){
    HSCSUGGESTIONLIST hSuggestions = GetSuggestions(hChecker, L"word", 4);
    const UINT cchBuffer = 256; //outlandishly large for a single word
    wchar_t* buffer = new wchar_t[cchBuffer]; 
    long score;
    CHECK_EQUAL((BOOL)false, GetNextSuggestion(hSuggestions, buffer, 0, &score));
    delete[] buffer;
    FreeSuggestions(hSuggestions);
}

TEST_FIXTURE(TestSpellCheckerFixture, GetNextSuggestion_NullScore_True){
    HSCSUGGESTIONLIST hSuggestions = GetSuggestions(hChecker, L"word", 4);
    const UINT cchBuffer = 256; //outlandishly large for a single word
    wchar_t* buffer = new wchar_t[cchBuffer]; 
    CHECK_EQUAL((BOOL)true, GetNextSuggestion(hSuggestions, buffer, cchBuffer, NULL));
    CHECK(std::wstring(L"word") == std::wstring(buffer));
    delete[] buffer;
    FreeSuggestions(hSuggestions);
}

TEST(FreeSuggestions_NullHandle_NoCrash){
    FreeSuggestions(NULL);
    testResults_;
}
